home *** CD-ROM | disk | FTP | other *** search
- /*
- * WRITE.C
- *
- * routines used to write to the screen
- *
- */
-
- #include "char.h"
-
- /*--------- external function prototypes: ---------*/
-
- /* look for unused key buffer */
- extern char *k_alloc (void);
- /* look for key buffer */
- extern char *k_seek (void);
- /* write decimal integer to ring buffer */
- extern void r_puti (char);
- /* write byte to ring buffer */
- extern void r_write (char);
- /* clear selected part of the screen */
- extern void rawclear (void);
- /* set the video mode */
- extern void rawmode (void);
- /* move the cursor */
- extern void rawmv (void);
- /* scroll the screen up */
- extern void rawscroll (void);
- /* output character as raw tty */
- extern void rawtty (void);
- /* output character to screen */
- extern void rawwrite (void);
-
-
- /*
- * delimiters used for quoted characters as
- * parameters of escape sequences
- */
-
- #define DELIM1 '\''
- #define DELIM2 '"'
-
- /*
- * characters that require special handling
- */
-
- #define BEL '\007'
- #define BS '\010'
- #define NL '\012'
- #define CR '\015'
- #define ESC '\033'
-
- /*
- * color codes
- */
-
- #define BLUE (01)
- #define GREEN (02)
- #define RED (04)
- #define CYAN (BLUE | GREEN)
- #define MAGENTA (BLUE | RED)
- #define YELLOW (GREEN | RED)
- #define WHITE (BLUE | GREEN | RED)
-
- /*
- * macro's for turning on and off attributes or designating
- * a color as foreground or background
- */
-
- #define ON(x) (attrib |= (char) (x))
- #define OFF(x) (attrib &= (char) (~(x)))
- #define FORE(x) (attrib |= (char) (x))
- #define BACK(x) (attrib |= (char) ((x) << 4))
-
- /*
- * we don't want to use the standard 'c' isdigit(); it's
- * either implemented as a function (we don't want to use
- * osmebody else's functions that might have unpleasant side
- * effects) or a macro invoking an array of values that
- * dictate what lexical properties a given character possesses
- * (a waste of precious memory)
- */
-
- #define isdigit(x) (((x) >= '0') && ((x) <= '9'))
-
- /*
- * w_write()
- *
- * w_write() keeps track of actually getting stuff on the screen
- * and moving the cursor around
- */
-
- void w_write()
- {
- switch (outchar)
- {
- case CR:
-
- /* just set the column to 0 for a carriage return */
-
- curr.loc.col = 0;
-
- /* and fall through to the backspace handler */
-
- case BS:
-
- /* decrement the current column unless at the left
- * margin */
-
- if (curr.loc.col)
- --curr.loc.col;
-
- /* move the cursor and that's it... */
-
- rawmv();
- break;
-
- default:
-
- /* first, write the character without
- moving the cursor */
-
- rawwrite();
-
- /* then, if we're not on the right margin, bump the
- * cursor right and that's it */
-
- if ((curr.loc.col + 1) <= max.loc.col)
- {
- ++curr.loc.col;
- rawmv();
- break;
- }
-
- /* but if we were at the right margin, check the wrap
- * flag; if it's clear, just return. if not, execute
- * a carriage return (just set the column to zero -
- * we'll do a rawmv() call later), set the current
- * character to newline, and fall into the newline
- * routine */
-
- if (!wrap)
- break;
- curr.loc.col = 0;
- outchar = NL;
- case NL:
-
- /* if we're not at the bottom of the screen, just bump
- * the line down and call rawmv() */
-
- if (++curr.loc.line < 25)
- {
- rawmv();
- break;
- }
-
- /* but if we were at the bottom (or somehow below!),
- * make sure we're on the bottom line. If we're in
- * one of the CGA 80x25 text modes, do our fancy
- * assembly language scroll routine, else just let
- * the BIOS handle it */
-
- curr.loc.line = 24;
- if (video_mode == 2 || video_mode == 3)
- {
- rawscroll();
- break;
- }
-
- case BEL:
-
- /* do a raw tty output; it handles the cursor movement
- * too */
-
- rawtty();
- break;
- }
- }
-
-
- /*
- * w_buffer()
- *
- * w_buffer() writes a byte into the escape buffer. silently
- * overwrites the last byte in the buffer if we get that far. it
- * was either that or trash the new byte
- */
-
- void w_buffer(c)
- char c;
- {
- if (char_cnt == BUF_LEN)
- esc_buf[ BUF_LEN - 1 ] = c;
- else
- esc_buf[ char_cnt++ ] = c;
- }
-
-
-
- /*
- * w_cursor()
- *
- * w_cursor() handles the cursor left, right, up and down
- * functions. bumps the value by the value of the 1st parameter
- * in the escape sequence (if there isn't one, we put a 1 in for
- * it) in the direction specified by the delta, until it hits the
- * specified limit. then execute the cursor move...
- */
-
- void w_cursor()
- {
- if (!char_cnt)
- esc_buf[ 0 ] = 1;
- while (*cur_val != limit)
- {
- *cur_val += delta;
- esc_buf[ 0 ]--;
- if (!esc_buf[ 0 ])
- break;
- }
- rawmv();
- }
-
-
-
- /*
- * w_putc()
- *
- * w_putc() updates the parameters that might have changed since
- * last time, then runs the character through the escape sequence
- * state machine
- */
-
- void w_putc()
- {
-
- /* update parameters */
-
- max.loc.col = SCREEN_WIDTH - 1;
- cur_page = CURRENT_PAGE;
- curr.position = (PAGE_TABLE[ cur_page ]).position;
- if (curr.loc.col > max.loc.col)
- curr.loc.col = max.loc.col;
- if ((video_mode = CURRENT_MODE) == 7)
- video_address = MONOCHROME + SCREEN_OFFSET;
- else
- video_address = GRAPHIC + SCREEN_OFFSET;
-
- /* process the escape sequence state */
-
- switch (state)
- {
-
- case HAVE_ESC:
-
- /* if we have an escape, we want a left bracket.
- * if we get it, change the state and return,
- * else reset back to the RAW state and fall
- * through */
-
- if (outchar == '[')
- {
- state = HAVE_LBRACE;
- break;
- }
- state = RAW;
-
- case RAW:
-
- /* if it's an escape, change the stae, else output the
- * character */
-
- if (outchar == ESC)
- state = HAVE_ESC;
- else
- w_write();
- break;
-
- case IN_NUMBER:
-
- /* if it's another digit, roll it into the value. else
- * the state falls back to HAVE_LBRACE, and we fall
- * through */
-
- if (isdigit(outchar))
- {
- tmp.value *= 10;
- tmp.value += outchar - '0';
- break;
- }
- else
- {
- state = HAVE_LBRACE;
- w_buffer(tmp.value);
- }
-
- case HAVE_LBRACE:
-
- /* if we have a string delimiter, change the state and
- * save the delimiter */
-
- if (outchar == DELIM1 || outchar == DELIM2)
- {
- state = IN_STRING;
- tmp.delim = outchar;
- break;
- }
-
- /* else if it's 'punctuation', ignore it */
-
- if (outchar == ';' || outchar == '=' ||
- outchar == '?')
- break;
-
- /* else if it's a digit, start a number and
- change the state */
-
- if (isdigit(outchar))
- {
- state = IN_NUMBER;
- tmp.value = outchar - '0';
- break;
- }
-
- /* else it terminates the escape sequence, and
- * identifies its purpose */
-
- switch (outchar)
- {
- case 'A': /* cursor up */
- limit = 0;
- delta = (char) -1;
- cur_val = &curr.loc.line;
- w_cursor();
- break;
-
- case 'B': /* cursor down */
- limit = 24;
- delta = 1;
- cur_val = &curr.loc.line;
- w_cursor();
- break;
-
- case 'C': /* cursor right */
- limit = max.loc.col;
- delta = 1;
- cur_val = &curr.loc.col;
- w_cursor();
- break;
-
- case 'D': /* cursor left */
- limit = 0;
- delta = (char) -1;
- cur_val = &curr.loc.col;
- w_cursor();
- break;
-
- case 'H':
- case 'R':
- case 'f':
-
- /* set cursor position: make sure there
- * are at least 2 parameters stored,
- * correct any out-of-range parameters,
- * and execute the move. if the
- * character was 'R', fall through into
- * the report position sequence */
-
- switch (char_cnt)
- {
- case 0:
- w_buffer(1);
- case 1:
- w_buffer(1);
- default:
- break;
- }
-
- if (!esc_buf[ 0 ])
- curr.loc.line = 1;
- else if (esc_buf[ 0 ] > 25)
- curr.loc.line = 25;
- else
- curr.loc.line = esc_buf[ 0 ];
-
- if (!esc_buf[ 1 ])
- curr.loc.col = 1;
- else if (esc_buf[ 1 ] > max.loc.col + 1)
- curr.loc.col = max.loc.col + 1;
- else
- curr.loc.col = esc_buf[ 1 ];
-
- curr.loc.line--;
- curr.loc.col--;
- rawmv();
-
- if (outchar != 'R')
- break;
-
- case 'n':
- /* output the position; format is
- * "\033[%.2d;%.2dR\015" */
-
- r_write(ESC);
- r_write('[');
- r_puti(curr.loc.line + 1);
- r_write(';');
- r_puti(curr.loc.col + 1);
- r_write('R');
- r_write(CR);
- break;
-
- case 'J':
- /* rawclear clears the screen from
- * (curr.loc.line, curr.loc.col) to
- * (max.loc.line, max.loc.col); so for
- * clear screen, set the current
- * position to the upper left hand
- * corner of the screen, and the max
- * line to the bottom of the screen */
-
- curr.loc.line = curr.loc.col = 0;
- max.loc.line = 24;
- rawclear();
- break;
-
- case 'K':
- /* and clear to end of line is even
- * simpler - just set the max line equal
- * to the same line we're on */
-
- max.loc.line = curr.loc.line;
- rawclear();
- break;
-
- case 'h':
- case 'l':
- /* set and reset mode do the same thing
- * unless the mode is 7. easy */
-
- if (!char_cnt)
- w_buffer(2);
- if (esc_buf[ 0 ] > 7)
- break;
- if (esc_buf[ 0 ] == 7)
- wrap = (char) (outchar == 'h');
- else
- rawmode();
- break;
-
- case 'm':
- /* set graphic rendition - just do all
- * the parameters and set/reset the
- * appropriate bits in the attribute
- * byte */
-
- while (char_cnt)
- {
- switch (esc_buf[ --char_cnt ])
- {
- case 0:
- attrib = 0007; break;
- case 1:
- ON(010); break;
- case 4:
- OFF(07); ON(01); break;
- case 5:
- ON(0200); break;
- case 7:
- OFF(07); ON(0160); break;
- case 8:
- OFF(0167); break;
- case 30:
- OFF(07); break;
- case 31:
- OFF(07); FORE(RED); break;
- case 32:
- OFF(07); FORE(GREEN); break;
- case 33:
- OFF(07); FORE(YELLOW); break;
- case 34:
- OFF(07); FORE(BLUE); break;
- case 35:
- OFF(07); FORE(MAGENTA); break;
- case 36:
- OFF(07); FORE(CYAN); break;
- case 37:
- OFF(07); FORE(WHITE); break;
- case 40:
- OFF(0160); break;
- case 41:
- OFF(0160); BACK(RED); break;
- case 42:
- OFF(0160); BACK(GREEN); break;
- case 43:
- OFF(0160); BACK(YELLOW); break;
- case 44:
- OFF(0160); BACK(BLUE); break;
- case 45:
- OFF(0160); BACK(MAGENTA); break;
- case 46:
- OFF(0160); BACK(CYAN); break;
- case 47:
- OFF(0160); BACK(WHITE); break;
- default:
- break;
- }
- }
- break;
- case 'p':
-
- if (esc_buf[ 0 ])
- {
-
- /* if the first parameter is not nul, then we're
- redefining a 'normal' key. Clear the msb of
- keycheck to indicate this */
-
- keycheck = (esc_buf[ 0 ]) &
- 0000377;
-
- /* check first to see if we've already allocated
- a buffer to this key; then if not, see if we have
- an unused buffer to hand out */
-
- if (k_seek() || k_alloc())
- {
- k = 1;
- kp->keystroke =
- (esc_buf[ 0 ])
- & 0000377;
- }
- else
- break;
- }
- else
- {
-
- /* first byte was nul - an extended key. indicate
- by setting msb of keycheck to $FF */
-
- keycheck = (esc_buf[ 1 ]) |
- 0177400;
- if (k_seek() || k_alloc())
- {
- k = 2;
- kp->keystroke =
- (esc_buf[ 1 ])
- | 0177400;
- }
- else
- break;
- }
-
- /* copy the parameters into the buffer, counting as we go */
-
- for (*len = 0; (k < char_cnt) &&
- (k < KEY_BUFLEN); ++*len)
- *ptr++ = esc_buf[ k++ ];
-
- break;
-
- case 's':
-
- /* save current position */
-
- saved.position = curr.position;
- break;
-
- case 'u':
-
- /* restore current position */
-
- curr.position = saved.position;
- rawmv();
- break;
-
- default:
-
- /* anything else? discard the parameters
- * and output the final character to the
- * screen */
-
- w_write();
- break;
- }
-
- /* finally, clear the buffer by resetting the count
- and fall back to the RAW state */
-
- char_cnt = 0;
- state = RAW;
- break;
-
- case IN_STRING:
-
- /* finally, the IN_STRING case - if the character
- * isn't the delimiter we saved, then put it into
- * the buffer as it was received */
-
- if (outchar == tmp.delim)
- state = HAVE_LBRACE;
- else
- w_buffer(outchar);
- break;
- }
- }
-